#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "os.h"
#include "filterapi.h"
#include "spts.h"

#define SPTS_DEBUG(fmt, ...) //SM_Printf(fmt, ##__VA_ARGS__)

static unsigned int s_u32SPTSMutex = 0;
#define SPTS_MUTEX_INIT()	SM_OsSemCreate(&s_u32SPTSMutex, NULL, 1)
#define SPTS_MUTEX_LOCK()	SM_OsSemWait(&s_u32SPTSMutex, (unsigned int)-1);
#define SPTS_MUTEX_UNLOCK()	SM_OsSemRelease(&s_u32SPTSMutex);

#define MAX_SPTS_ES	10

typedef struct 
{
	unsigned int		m_u32Started;
	pfSPTSDataGot	m_pfSptsOutput;
	pfNotifyPlayer		m_pfPlayerNotification;
	spts_status_t 		m_eStatus;

	filter_handle_t 	m_hSecPat;
	filter_handle_t 	m_hTsPcr;
	filter_handle_t 	m_hTsPat;
	filter_handle_t 	m_hTsPmt;
	filter_handle_t 	m_ahTsEs[MAX_SPTS_ES];
	unsigned int		m_u32EsEncryContinusCnt[MAX_SPTS_ES];
	unsigned char 	m_u8EsEncryState[MAX_SPTS_ES];//0:not detect, 1:free, 2:encry
	unsigned char 	m_u8EncryProgram;//0:not detect, 1:free, 2:encry
	unsigned char 	m_u8Paused;

	unsigned short	m_u16PmtPid;
	unsigned char		m_u8PatCc;
	unsigned char		m_u8PmtCc;
	unsigned char		m_au8TsPat[204];
	unsigned char		m_au8TsPmt[188*6];
	unsigned char		m_u8PmtPacketCnt;
	spts_param_t		m_stSptsParam;
}spts_t;

typedef struct
{
	unsigned short	m_u16Len;
	unsigned char*	m_pu8Info;
}spts_info_t;

typedef struct 
{
	unsigned short	m_u16ServiceId;
	unsigned short	m_u16PcrPid;
	unsigned short	m_u16PmtPid;
	spts_info_t		m_stProgInfo;
	spts_es_t		m_astEs[2];
	spts_info_t		m_astEsInfo[2];
}spts_pmt_param_t;

typedef enum
{
	SPTS_OUTPUT_NORMAL,
	SPTS_OUTPUT_STOP,
}SPTS_OUTPUT_T;

spts_t* pstSpts;

#define SPTS_OUTPUT_PACKET_NUM	160
static unsigned int u32TatolLen = 0;
static unsigned char szBuffer[(SPTS_OUTPUT_PACKET_NUM+5)*188];
static unsigned char au8AC3Desc[] = {0x05, 0x04, 0x41, 0x43, 0x2d, 0x33};

#define SPTS_CRC32_POLY	0x04C11DB7  	/**/
static unsigned int u32CRC32Table[256];									/**/
/******************************************************************************

******************************************************************************/
static void SPTS_CreateCRC32Table(unsigned int u32Poly)
{
	unsigned int i, j,c;

	for (i = 0; i < 256; ++i) 
	{
		for (c = i << 24, j = 8; j > 0; --j)
			c = c & 0x80000000 ? (c << 1) ^ u32Poly : (c << 1);
		u32CRC32Table[i] = c;
	}
}
/******************************************************************************

******************************************************************************/
unsigned int  SPTS_GetCRC32(unsigned char *pu8Buf, unsigned int u32Len)
{
	unsigned char *p;
	unsigned long  crc = 0xFFFFFFFF;

	for (p = pu8Buf; u32Len > 0; ++p, --u32Len)
		crc = (crc << 8) ^ u32CRC32Table[(crc >> 24) ^ *p];
	return crc;
}

//one packet
static int SPTS_ConstructPat(unsigned short u16Serviceid, unsigned short u16PmtPid)
{
	int rc = 0;
	unsigned int u32Index;
	unsigned int u32Crc;

	SPTS_DEBUG("SPTS_ConstructPat entry, u16Serviceid = %d, u16PmtPid = %d\r\n", u16Serviceid, u16PmtPid);
	
	u32Index = 0;
	pstSpts->m_au8TsPat[u32Index++] = 0x47;
	pstSpts->m_au8TsPat[u32Index++] = 0x40;//payload start 
	pstSpts->m_au8TsPat[u32Index++] = 0x00;
	pstSpts->m_au8TsPat[u32Index++] = 0x10;//afc=1, cc=0
	pstSpts->m_au8TsPat[u32Index++] = 0x00;//pointer field

	pstSpts->m_au8TsPat[u32Index++] = 0x00;//table id
	pstSpts->m_au8TsPat[u32Index++] = 0xB0;
	pstSpts->m_au8TsPat[u32Index++] = 0x00;//section len
	pstSpts->m_au8TsPat[u32Index++] = 0x00;
	pstSpts->m_au8TsPat[u32Index++] = 0x01;//ts id
	pstSpts->m_au8TsPat[u32Index++] = 0xC1;//version num 0, current next indictor 1
	pstSpts->m_au8TsPat[u32Index++] = 0x00;//section nb
	pstSpts->m_au8TsPat[u32Index++] = 0x00;//last section nb

	pstSpts->m_au8TsPat[u32Index++] = (unsigned char)(u16Serviceid>>8);
	pstSpts->m_au8TsPat[u32Index++] = (unsigned char)u16Serviceid;
	pstSpts->m_au8TsPat[u32Index++] = (unsigned char)(u16PmtPid>>8);
	pstSpts->m_au8TsPat[u32Index++] = (unsigned char)u16PmtPid;

	//crc
	pstSpts->m_au8TsPat[u32Index++] = 0x00;
	pstSpts->m_au8TsPat[u32Index++] = 0x00;
	pstSpts->m_au8TsPat[u32Index++] = 0x00;
	pstSpts->m_au8TsPat[u32Index++] = 0x00;

	pstSpts->m_au8TsPat[7] = u32Index - 8;

	u32Crc = SPTS_GetCRC32(&pstSpts->m_au8TsPat[5], u32Index-9);
	pstSpts->m_au8TsPat[u32Index-4] = (unsigned char)(u32Crc>>24);
	pstSpts->m_au8TsPat[u32Index-3] = (unsigned char)(u32Crc>>16);
	pstSpts->m_au8TsPat[u32Index-2] = (unsigned char)(u32Crc>>8);
	pstSpts->m_au8TsPat[u32Index-1] = (unsigned char)(u32Crc>>0);

	u32Crc = SPTS_GetCRC32(&pstSpts->m_au8TsPat[5], u32Index-9);

	memset(&pstSpts->m_au8TsPat[u32Index], 0xFF, 188-u32Index);
	SPTS_DEBUG("SPTS_ConstructPat return\r\n");

	return rc;
}

static int SPTS_ConstructPmtSection(spts_pmt_param_t* pstPmtParm, unsigned char* pu8Pmt)
{
	unsigned int u32Index;
	unsigned int u32Crc;
	unsigned int i;

	u32Index = 0;
	pu8Pmt[u32Index++] = 0x02;//table id
	pu8Pmt[u32Index++] = 0xB0;
	pu8Pmt[u32Index++] = 0x00;//section len
	pu8Pmt[u32Index++] = (unsigned char)(pstPmtParm->m_u16ServiceId>>8);
	pu8Pmt[u32Index++] = (unsigned char)(pstPmtParm->m_u16ServiceId>>0);
	pu8Pmt[u32Index++] = 0xC1;//version num 0, current next indictor 1
	pu8Pmt[u32Index++] = 0x00;//section nb
	pu8Pmt[u32Index++] = 0x00;//last section nb
	pu8Pmt[u32Index++] = 0xE0|((pstPmtParm->m_u16PcrPid>>8)&0x1F);
	pu8Pmt[u32Index++] = (unsigned char)pstPmtParm->m_u16PcrPid;

	//program info, no program info now
	pu8Pmt[u32Index++] = 0xF0;
	pu8Pmt[u32Index++] = 0x00;

	//es info
	for(i=0; i<2; i++)
	{
		pu8Pmt[u32Index++] = pstPmtParm->m_astEs[i].m_u32Type;
		pu8Pmt[u32Index++] = 0xE0|((pstPmtParm->m_astEs[i].m_u16Pid>>8)&0x1F);
		pu8Pmt[u32Index++] = (unsigned char)pstPmtParm->m_astEs[i].m_u16Pid;

		pu8Pmt[u32Index++] = 0xF0|((unsigned char)(pstPmtParm->m_astEsInfo[i].m_u16Len>>8));
		pu8Pmt[u32Index++] = (unsigned char)(pstPmtParm->m_astEsInfo[i].m_u16Len>>0);
		memcpy(&pu8Pmt[u32Index], pstPmtParm->m_astEsInfo[i].m_pu8Info, pstPmtParm->m_astEsInfo[i].m_u16Len);
		u32Index += pstPmtParm->m_astEsInfo[i].m_u16Len;
	}

	//crc
	pu8Pmt[u32Index++] = 0x00;
	pu8Pmt[u32Index++] = 0x00;
	pu8Pmt[u32Index++] = 0x00;
	pu8Pmt[u32Index++] = 0x00;

	pu8Pmt[1] = 0xB0|((u32Index-3)>>8);
	pu8Pmt[2] = (unsigned char)(u32Index -3);//section len

	u32Crc = SPTS_GetCRC32(pu8Pmt, u32Index-4);
	pu8Pmt[u32Index-4] = (unsigned char)(u32Crc>>24);
	pu8Pmt[u32Index-3] = (unsigned char)(u32Crc>>16);
	pu8Pmt[u32Index-2] = (unsigned char)(u32Crc>>8);
	pu8Pmt[u32Index-1] = (unsigned char)(u32Crc>>0);

	return 0;
}

static int SPTS_ConstructPmt(spts_pmt_param_t* pstPmtParm)
{
	int rc = 0;
	unsigned int u32Index;
	unsigned char u8Pmt[1024];
	unsigned short u16PmtLen;
	unsigned short u16CopiedLen;
	unsigned short u16Size2Copy;

	SPTS_DEBUG("SPTS_ConstructPmt entry, u16Serviceid = %d, u16PcrPid = %d, u16PmtPid = %d, pstEsInfo = %p, u32EsCnt = %d\r\n");

	SPTS_ConstructPmtSection(pstPmtParm, u8Pmt);
	u16PmtLen = ((u8Pmt[1]&0x0F)<<8)|u8Pmt[2];
	u16PmtLen += 3;

	u32Index = 0;
	memset(pstSpts->m_au8TsPmt, 0xFF, sizeof(pstSpts->m_au8TsPmt));
	pstSpts->m_au8TsPmt[u32Index++] = 0x47;
	pstSpts->m_au8TsPmt[u32Index++] = 0x40|((pstPmtParm->m_u16PmtPid>>8)&0x1F);//payload start 
	pstSpts->m_au8TsPmt[u32Index++] = (unsigned char)pstPmtParm->m_u16PmtPid;
	pstSpts->m_au8TsPmt[u32Index++] = 0x10;//afc=1, cc=0
	pstSpts->m_au8TsPmt[u32Index++] = 0x00;//pointer field
	pstSpts->m_u8PmtPacketCnt = 1;
	if(u16PmtLen > 183)
	{
		memcpy(&pstSpts->m_au8TsPmt[u32Index], u8Pmt, 183);
		u32Index += 183;
		u16CopiedLen = 183;
		do 
		{
			pstSpts->m_au8TsPmt[u32Index++] = 0x47;
			pstSpts->m_au8TsPmt[u32Index++] = (pstPmtParm->m_u16PmtPid>>8)&0x1F;//payload start 
			pstSpts->m_au8TsPmt[u32Index++] = (unsigned char)pstPmtParm->m_u16PmtPid;
			pstSpts->m_au8TsPmt[u32Index++] = 0x10;//afc=1, cc=0
			u16Size2Copy = ((u16PmtLen-u16CopiedLen>184) ? 184:u16PmtLen-u16CopiedLen);
			memcpy(&pstSpts->m_au8TsPmt[u32Index], u8Pmt+u16CopiedLen, u16Size2Copy);
			u32Index += u16Size2Copy;
			u16CopiedLen += u16Size2Copy;
			pstSpts->m_u8PmtPacketCnt++;
		}while (u16CopiedLen < u16PmtLen);
	}
	else
	{
		memcpy(&pstSpts->m_au8TsPmt[u32Index], u8Pmt, u16PmtLen);
	}

	SPTS_DEBUG("SPTS_ConstructPmt return\r\n");

	return rc;
}

static int SPTS_UpdateOutputStatus(filter_handle_t hfilter)
{
	unsigned int rc = 0;

	SPTS_DEBUG("SPTS_UpdateOutputStatus entry, hfilter = 0x%x\r\n", hfilter);
	if(pstSpts->m_ahTsEs[0] == hfilter)
	{
		pstSpts->m_eStatus |= SPTS_OUTPUT_VIDEO_OK;
	}
	else if(pstSpts->m_ahTsEs[1] == hfilter )
	{
		pstSpts->m_eStatus |= SPTS_OUTPUT_AUDIO_OK;
	}
	else
	{
		rc = -1;
	}
	SPTS_DEBUG("SPTS_UpdateOutputStatus return rc = %d\r\n", rc);
	return rc;
}

static int SPTS_UpdateScrambleStatus(filter_handle_t hfilter, unsigned char u8Encry)
{
	unsigned int rc = 0;
	spts_scramble_status_t eStatus;
	unsigned int i;

	SPTS_DEBUG("SPTS_UpdateScrambleStatus entry, hfilter = 0x%x, u8Encry = %d\r\n", hfilter, u8Encry);

	if(u8Encry > 0)
		eStatus = SPTS_ENCRYTION_SCRAMBLE;
	else
		eStatus = SPTS_ENCRYTION_FREE;
	
	for(i=0; i<pstSpts->m_stSptsParam.m_u16EsCnt; i++)
	{
		if(pstSpts->m_ahTsEs[i] == hfilter)
		{
			pstSpts->m_u8EsEncryState[i] = eStatus;//free
			if(eStatus == SPTS_ENCRYTION_SCRAMBLE)
				pstSpts->m_u32EsEncryContinusCnt[i]++;
			else
				pstSpts->m_u32EsEncryContinusCnt[i] = 0;
		}

		if(pstSpts->m_stSptsParam.m_astEs[i].m_u16Pid == 0x1FFF)
		{
			pstSpts->m_u32EsEncryContinusCnt[i] = 0;
			pstSpts->m_u8EsEncryState[i] = SPTS_ENCRYTION_FREE;
		}
	}
	
	SPTS_DEBUG("SPTS_UpdateScrambleStatus return rc = %d\r\n", rc);
	return rc;
}

static unsigned char au8NullPacket[188] = 
{
	0x47, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

static unsigned int u8RecievePacketCnt = 0;

static int SPTS_TSDataGot(filter_handle_t hfilter,  unsigned char* pu8Data,  unsigned short u16Datalen)
{
	int rc = 0;
	unsigned char* pu8Output = NULL;
	unsigned int i = 0;
	unsigned char u8Encry = 0;
	unsigned char u8Afc;
	unsigned char u8AllEsFree = 1;

	SPTS_DEBUG("SPTS_TSDataGot entry, hfilter = %d, pu8Data = %p, u16Datalen = %d\r\n", hfilter, pu8Data, u16Datalen);

	u8RecievePacketCnt++;
	SPTS_MUTEX_LOCK();
	if(pstSpts->m_u8Paused == SPTS_OUTPUT_STOP)
	{
		SPTS_MUTEX_UNLOCK();
		return 0;
	}
	
	if(pstSpts->m_hTsPat == hfilter)
	{
		pstSpts->m_au8TsPat[3] = (pstSpts->m_au8TsPat[3]&0xF0)|(pstSpts->m_u8PatCc&0x0F);
		pu8Output = pstSpts->m_au8TsPat;
		pstSpts->m_u8PatCc++;
	}
	else if(pstSpts->m_hTsPmt == hfilter)
	{
		i = 0;
		pu8Output = pstSpts->m_au8TsPmt;
		do
		{
			pstSpts->m_au8TsPmt[i*188+3] = (pstSpts->m_au8TsPmt[i*188+3]&0xF0)|(pstSpts->m_u8PmtCc&0x0F);
			pstSpts->m_u8PmtCc++;
			i++;
		}while(i<pstSpts->m_u8PmtPacketCnt);
		u16Datalen = pstSpts->m_u8PmtPacketCnt*188;
	}
	else
	{
		SPTS_UpdateOutputStatus(hfilter);
		u8Afc = (pu8Data[3]>>4)&0x03;
		if(u8Afc == 0x01 || u8Afc == 0x3)//only adapt field, encry flag not detect
		{
			u8Encry = pu8Data[3]>>6;
			SPTS_UpdateScrambleStatus(hfilter, u8Encry);
			if(u8Encry)
			{
				if(pstSpts->m_u8EncryProgram != SPTS_ENCRYTION_SCRAMBLE)
				{
					if(pstSpts->m_u32EsEncryContinusCnt[0] > 5 || pstSpts->m_u32EsEncryContinusCnt[1] > 5)//all es scramble notify upper layer
					{
						if(pstSpts->m_pfPlayerNotification)
						{
							SM_Printf("*******encry ts packet: %02x, %02x, %02x, %02x\r\n", pu8Data[0], pu8Data[1], pu8Data[2], pu8Data[3]);
							pstSpts->m_pfPlayerNotification(SPTS_STREAM_ENCRY);
						}
						pstSpts->m_u8EncryProgram = SPTS_ENCRYTION_SCRAMBLE;
					}
				}
			}
			else if(u8Encry==0 && pstSpts->m_u8EncryProgram!=SPTS_ENCRYTION_FREE)//非加密es，未通知上层
			{
				for(i=0; i<pstSpts->m_stSptsParam.m_u16EsCnt; i++)
				{
					if(pstSpts->m_ahTsEs[i]!=INVALID_FILTER_HANDLE && pstSpts->m_u8EsEncryState[i]!=SPTS_ENCRYTION_FREE)
					{
						u8AllEsFree = 0;
					}
				}

				if(u8AllEsFree == 1)
				{
					//notify upper layer
					if(pstSpts->m_pfPlayerNotification)
						pstSpts->m_pfPlayerNotification(SPTS_STREAM_FREE);
					pstSpts->m_u8EncryProgram = SPTS_ENCRYTION_FREE;
					
					//SM_Printf("********acquanting OK*********Video[handle:%x, pid:%x, encry:%d], Audio[handle: %x, pid:%x, encry:%d], TS[%02x, %02x, %02x, %02x]\r\n",
					//	pstSpts->m_ahTsEs[0], pstSpts->m_stSptsParam.m_astEs[0].m_u16Pid, pstSpts->m_u8EsEncryState[0],
					//	pstSpts->m_ahTsEs[1], pstSpts->m_stSptsParam.m_astEs[1].m_u16Pid, pstSpts->m_u8EsEncryState[1],
					//	pu8Data[0], pu8Data[1], pu8Data[2], pu8Data[3]);

				}
				else
				{
					//SM_Printf("********acquanting*********Video[handle:%x, pid:%x, encry:%d], Audio[handle: %x, pid:%x, encry:%d], TS[%02x, %02x, %02x, %02x]\r\n",
					//	pstSpts->m_ahTsEs[0], pstSpts->m_stSptsParam.m_astEs[0].m_u16Pid, pstSpts->m_u8EsEncryState[0],
					//	pstSpts->m_ahTsEs[1], pstSpts->m_stSptsParam.m_astEs[1].m_u16Pid, pstSpts->m_u8EsEncryState[1],
					//	pu8Data[0], pu8Data[1], pu8Data[2], pu8Data[3]);
				}
			}
		}		
		pu8Output = pu8Data;
	}

	if(pstSpts->m_u8EncryProgram == SPTS_ENCRYTION_FREE)//only output fta
	{
		memcpy(szBuffer+u32TatolLen, pu8Output, u16Datalen);
		u32TatolLen += u16Datalen;

		if(u32TatolLen >= SPTS_OUTPUT_PACKET_NUM*188)
		{			
			if(pstSpts->m_pfSptsOutput)
				pstSpts->m_pfSptsOutput(szBuffer, u32TatolLen);
			u32TatolLen = 0;
		}
	}
	else if(u8RecievePacketCnt%100 == 0)
	{
		pstSpts->m_pfSptsOutput(au8NullPacket, 188);
	}

	SPTS_MUTEX_UNLOCK();
	
	SPTS_DEBUG("SPTS_TSDataGot return\r\n");

	return rc;
}

static int SPTS_StartEs()
{
	filter_pid_param_t stTsParam;
	int rc = 0;
	unsigned int i;
	unsigned char u8PcrNeedStart = 1;

	SPTS_DEBUG("SPTS_StartEs entry\r\n");

	pstSpts->m_u8EncryProgram = SPTS_ENCRYTION_UNKNOWED;
	memset(pstSpts->m_u32EsEncryContinusCnt, 0, sizeof(pstSpts->m_u32EsEncryContinusCnt));
	pstSpts->m_hTsPcr = INVALID_FILTER_HANDLE;
	for(i=0; i<pstSpts->m_stSptsParam.m_u16EsCnt; i++)
	{
		if(pstSpts->m_stSptsParam.m_astEs[i].m_u16Pid == 0x1FFF)
		{
			continue;
		}
		if(pstSpts->m_stSptsParam.m_astEs[i].m_u16Pid == pstSpts->m_stSptsParam.m_u16PcrPid)
			u8PcrNeedStart = 0;
		stTsParam.m_pfCallback = SPTS_TSDataGot;
		stTsParam.m_u16Pid = pstSpts->m_stSptsParam.m_astEs[i].m_u16Pid;
		Filter_StartPidFilter(&stTsParam, &pstSpts->m_ahTsEs[i]);
		pstSpts->m_u8EsEncryState[i] = SPTS_ENCRYTION_UNKNOWED;
	}

	if(u8PcrNeedStart == 1)
	{
		stTsParam.m_pfCallback = SPTS_TSDataGot;
		stTsParam.m_u16Pid = pstSpts->m_stSptsParam.m_u16PcrPid;
		Filter_StartPidFilter(&stTsParam, &pstSpts->m_hTsPcr);
	}

	if(pstSpts->m_pfPlayerNotification)
		pstSpts->m_pfPlayerNotification(SPTS_SI_OK);

	SPTS_DEBUG("SPTS_StartEs return\r\n");

	return rc;
}

int PmtDataGotCb(filter_handle_t hFilter, unsigned char* pu8Data, unsigned short u16Datalen)
{
	int rc = 0;
	unsigned int u32Index;
	unsigned short u16ProNum;
	spts_pmt_param_t stPmtConstructParam;
	unsigned short u16EsPid;
	unsigned short u16EsInfoLen;
	filter_pid_param_t stTsParam;

	SPTS_DEBUG("PmtDataGotCb entry, hFilter = %d, pu8Data = %p, u16Datalen = %d\r\n", hFilter, pu8Data, u16Datalen);

	SPTS_MUTEX_LOCK();
	u32Index = 3;
	u16ProNum = pu8Data[u32Index++];
	u16ProNum = (u16ProNum<<8)|pu8Data[u32Index++];

	if(u16ProNum == pstSpts->m_stSptsParam.m_u16ServiceId)
	{
		memset(&stPmtConstructParam, 0, sizeof(stPmtConstructParam));

		stPmtConstructParam.m_u16PmtPid = pstSpts->m_u16PmtPid;
		stPmtConstructParam.m_u16ServiceId = pstSpts->m_stSptsParam.m_u16ServiceId;
		stPmtConstructParam.m_u16PcrPid = pstSpts->m_stSptsParam.m_u16PcrPid;

		u32Index = 10;
		stPmtConstructParam.m_stProgInfo.m_u16Len = pu8Data[u32Index++]&0x0F;
		stPmtConstructParam.m_stProgInfo.m_u16Len = (stPmtConstructParam.m_stProgInfo.m_u16Len<<8)|pu8Data[u32Index++];
		stPmtConstructParam.m_stProgInfo.m_pu8Info = &pu8Data[u32Index];

		stPmtConstructParam.m_astEs[0] = pstSpts->m_stSptsParam.m_astEs[0];
		stPmtConstructParam.m_astEs[1] = pstSpts->m_stSptsParam.m_astEs[1];

		u32Index += stPmtConstructParam.m_stProgInfo.m_u16Len;
		while(u32Index < u16Datalen-4)
		{
			u32Index++;
			u16EsPid = pu8Data[u32Index++]&0x1F;
			u16EsPid = (u16EsPid<<8)|pu8Data[u32Index++];
			u16EsInfoLen = pu8Data[u32Index++]&0xF;
			u16EsInfoLen = (u16EsInfoLen<<8)|pu8Data[u32Index++];
			if(u16EsPid == stPmtConstructParam.m_astEs[0].m_u16Pid)
			{
				stPmtConstructParam.m_astEsInfo[0].m_u16Len = u16EsInfoLen;
				stPmtConstructParam.m_astEsInfo[0].m_pu8Info = &pu8Data[u32Index];
				if(stPmtConstructParam.m_astEs[0].m_u32Type == 0x06 && stPmtConstructParam.m_astEsInfo[0].m_u16Len == 0)
				{
					stPmtConstructParam.m_astEsInfo[0].m_pu8Info = au8AC3Desc;
					stPmtConstructParam.m_astEsInfo[0].m_u16Len = sizeof(au8AC3Desc);
				}
			}
			else if(u16EsPid == stPmtConstructParam.m_astEs[1].m_u16Pid)
			{
				stPmtConstructParam.m_astEsInfo[1].m_u16Len = u16EsInfoLen;
				stPmtConstructParam.m_astEsInfo[1].m_pu8Info = &pu8Data[u32Index];
				if(stPmtConstructParam.m_astEs[1].m_u32Type == 0x06 && stPmtConstructParam.m_astEsInfo[1].m_u16Len == 0)
				{
					stPmtConstructParam.m_astEsInfo[1].m_pu8Info = au8AC3Desc;
					stPmtConstructParam.m_astEsInfo[1].m_u16Len = sizeof(au8AC3Desc);
				}
			}
			u32Index += u16EsInfoLen;
		}
		SPTS_ConstructPmt(&stPmtConstructParam);
		Filter_StopSectionFilter(pstSpts->m_hSecPat);
		pstSpts->m_hSecPat = INVALID_FILTER_HANDLE;

		stTsParam.m_u16Pid = pstSpts->m_u16PmtPid;
		stTsParam.m_pfCallback = SPTS_TSDataGot;
		Filter_StartPidFilter(&stTsParam, &pstSpts->m_hTsPmt);
		SPTS_StartEs();
	}
	else
	{
		SPTS_DEBUG("PmtDataGotCb receive last program pmt\r\n");
		rc = -1;
	}

	SPTS_MUTEX_UNLOCK();

	SPTS_DEBUG("PmtDataGotCb return\r\n");

	return rc;
}


static int SPTS_StartPmt(unsigned short u16PmtPid)
{
	filter_section_param_t stSecparam;
	unsigned short au16SectByte[16];

	SPTS_DEBUG("SPTS_StartPmt entry\r\n");
	memset(au16SectByte, 0, sizeof(au16SectByte));
	au16SectByte[0] = 0xFF02;
	stSecparam.m_pu16SectByte = au16SectByte;
	stSecparam.m_u16Pid = u16PmtPid;
	stSecparam.m_u8CrcCheck = 1;
	stSecparam.m_u8FilterDepth = 1;
	stSecparam.m_pfCallback = PmtDataGotCb;

	Filter_StartSectionFilter(&stSecparam, &pstSpts->m_hSecPat);

	SPTS_DEBUG("SPTS_StartPmt return\r\n");

	return 0;
}

int PatDataGotCb(filter_handle_t hFilter, unsigned char* pu8Data, unsigned short u16Datalen)
{
	int rc = 0;
	unsigned int u32Index;
	unsigned short u32ProNum;
	unsigned short u16PmtPid = 0x1FFF;
	filter_pid_param_t stTsParam;

	SPTS_DEBUG("PatDataGotCb entry, hFilter = %d, pu8Data = %p, u16Datalen = %d\r\n", hFilter, pu8Data, u16Datalen);

	SPTS_MUTEX_LOCK();
	if(pu8Data[0] == 0)
	{
		//找到对应节目的pmt pid
		u32Index = 8;
		while(u32Index < u16Datalen)
		{
			u32ProNum = pu8Data[u32Index++];
			u32ProNum = (u32ProNum<<8)|pu8Data[u32Index++];
			if(u32ProNum == pstSpts->m_stSptsParam.m_u16ServiceId)
			{
				u16PmtPid = pu8Data[u32Index]&0x1F;
				u16PmtPid = (u16PmtPid<<8)|pu8Data[u32Index+1];
				pstSpts->m_u16PmtPid = u16PmtPid;
				break;
			}
			u32Index += 2;
		}

		//启动pat TS包过滤
		if(u16PmtPid != 0x1FFF)
		{
			SPTS_ConstructPat(pstSpts->m_stSptsParam.m_u16ServiceId, u16PmtPid);
			//SPTS_ConstructPmt(pstSpts->m_stSptsParam.m_u16ServiceId, pstSpts->m_stSptsParam.m_u16PcrPid, u16PmtPid, pstSpts->m_stSptsParam.m_astEs, pstSpts->m_stSptsParam.m_u16EsCnt);

			stTsParam.m_u16Pid = 0;
			stTsParam.m_pfCallback = SPTS_TSDataGot;
			Filter_StartPidFilter(&stTsParam, &pstSpts->m_hTsPat);

			Filter_StopSectionFilter(pstSpts->m_hSecPat);
			SPTS_StartPmt(u16PmtPid);
		}
	}
	else
	{
		SPTS_DEBUG("PatDataGotCb recv error table id %x\r\n", pu8Data[0]);
	}
	SPTS_MUTEX_UNLOCK();

	SPTS_DEBUG("PatDataGotCb return\r\n");

	return rc;
}

static int SPTS_StartPat()
{
	filter_section_param_t stSecparam;
	unsigned short au16SectByte[16];

	SPTS_DEBUG("SPTS_StartPat entry\r\n");
	memset(au16SectByte, 0, sizeof(au16SectByte));
	au16SectByte[0] = 0xFF00;
	stSecparam.m_pu16SectByte = au16SectByte;
	stSecparam.m_u16Pid = 0;
	stSecparam.m_u8CrcCheck = 1;
	stSecparam.m_u8FilterDepth = 1;
	stSecparam.m_pfCallback = PatDataGotCb;

	Filter_StartSectionFilter(&stSecparam, &pstSpts->m_hSecPat);

	SPTS_DEBUG("SPTS_StartPat return\r\n");

	return 0;
}

static int SPTS_FreeFilter()
{
	unsigned int i;

	SPTS_DEBUG("SPTS_SetFilter entry\r\n");

	//stop pat
	if(pstSpts->m_hSecPat != INVALID_FILTER_HANDLE)
	{
		Filter_StopSectionFilter(pstSpts->m_hSecPat);
		pstSpts->m_hSecPat = INVALID_FILTER_HANDLE;
	}

	if(pstSpts->m_hTsPcr != INVALID_FILTER_HANDLE)
	{
		Filter_StopPidFilter(pstSpts->m_hTsPcr);
		pstSpts->m_hTsPcr = INVALID_FILTER_HANDLE;
	}
	if(pstSpts->m_hTsPat != INVALID_FILTER_HANDLE)
	{
		Filter_StopPidFilter(pstSpts->m_hTsPat);
		pstSpts->m_hTsPat = INVALID_FILTER_HANDLE;
	}
	if(pstSpts->m_hTsPmt != INVALID_FILTER_HANDLE)
	{
		Filter_StopPidFilter(pstSpts->m_hTsPmt);
		pstSpts->m_hTsPmt = INVALID_FILTER_HANDLE;
	}

	pstSpts->m_u8PatCc = 0;
	pstSpts->m_u8PmtCc = 0;

	for(i=0; i<MAX_SPTS_ES; i++)
	{
		if(pstSpts->m_ahTsEs[i] != INVALID_FILTER_HANDLE)
		{
			Filter_StopPidFilter(pstSpts->m_ahTsEs[i]);
			pstSpts->m_ahTsEs[i] = INVALID_FILTER_HANDLE;
		}
	}
	SPTS_DEBUG("SPTS_SetFilter return\r\n");

	return 0;
}

int SPTS_Recognise()
{
	SPTS_DEBUG("SPTS_Recognise entry\r\n");
	if(!pstSpts || pstSpts->m_stSptsParam.m_u16EsCnt==0)
	{
		SPTS_DEBUG("SPTS_Recognise found NULL s_pstSptsParam or no es\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	pstSpts->m_u8EncryProgram = SPTS_ENCRYTION_UNKNOWED;
	memset(pstSpts->m_u32EsEncryContinusCnt, 0, sizeof(pstSpts->m_u32EsEncryContinusCnt));
	memset(pstSpts->m_u8EsEncryState, SPTS_ENCRYTION_UNKNOWED, sizeof(pstSpts->m_u8EsEncryState));
	SPTS_MUTEX_UNLOCK();
	
	SPTS_DEBUG("SPTS_Recognise return 0\r\n");

	return 0;
}

int SPTS_OutputPause()
{
	SPTS_DEBUG("SPTS_OutputPause entry\r\n");
	if(!pstSpts || pstSpts->m_stSptsParam.m_u16EsCnt==0)
	{
		SPTS_DEBUG("SPTS_OutputPause found NULL s_pstSptsParam or no es\r\n");
		return -1;
	}
	
	SPTS_MUTEX_LOCK();
	pstSpts->m_u8Paused = SPTS_OUTPUT_STOP;
	SPTS_MUTEX_UNLOCK();
	
	SPTS_DEBUG("SPTS_OutputPause return 0\r\n");

	return 0;
}

int SPTS_OutputResume()
{
	SPTS_DEBUG("SPTS_OutputResume entry\r\n");
	if(!pstSpts || pstSpts->m_stSptsParam.m_u16EsCnt==0)
	{
		SPTS_DEBUG("SPTS_OutputResume found NULL s_pstSptsParam or no es\r\n");
		return -1;
	}
	
	SPTS_MUTEX_LOCK();
	pstSpts->m_u8Paused = SPTS_OUTPUT_NORMAL;
	SPTS_MUTEX_UNLOCK();
	
	SPTS_DEBUG("SPTS_OutputResume return 0\r\n");

	return 0;
}

int SPTS_OutputStart ()
{
	filter_pid_param_t stTsParam;
	
	SPTS_DEBUG("SPTS_OutputStart entry\r\n");
	if(!pstSpts || pstSpts->m_stSptsParam.m_u16EsCnt==0)
	{
		SPTS_DEBUG("SPTS_OutputStart found NULL s_pstSptsParam or no es\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	if(pstSpts->m_u32Started == 1)
	{
		SPTS_FreeFilter();
	}

	u32TatolLen = 0;//clear buffer
	if(pstSpts->m_stSptsParam.m_u16PmtPid != 0x1FFF)
	{
		SPTS_ConstructPat(pstSpts->m_stSptsParam.m_u16ServiceId, pstSpts->m_stSptsParam.m_u16PmtPid);
		stTsParam.m_u16Pid = 0;
		stTsParam.m_pfCallback = SPTS_TSDataGot;
		Filter_StartPidFilter(&stTsParam, &pstSpts->m_hTsPat);
		pstSpts->m_u16PmtPid = pstSpts->m_stSptsParam.m_u16PmtPid;
		SPTS_StartPmt(pstSpts->m_stSptsParam.m_u16PmtPid);
	}
	else
	{
		SPTS_StartPat();	
	}
	pstSpts->m_u32Started = 1;
	pstSpts->m_u8Paused = 0;
	pstSpts->m_eStatus = SPTS_OUTPUT_ALL_ES_OK;//default all ok
	SPTS_MUTEX_UNLOCK();

	SPTS_DEBUG("SPTS_OutputStart return 0\r\n");

	return 0;
}

int SPTS_OutputStop ()
{
	SPTS_DEBUG("SPTS_OutputStop entry\r\n");

	if(!pstSpts || pstSpts->m_stSptsParam.m_u16EsCnt==0)
	{
		SPTS_DEBUG("SPTS_OutputStop found NULL s_pstSptsParam or no es\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	if(pstSpts->m_u32Started == 1)
	{
		SPTS_FreeFilter();
	}
	pstSpts->m_u32Started = 0;
	SPTS_MUTEX_UNLOCK();

	SPTS_DEBUG("SPTS_OutputStop return 0\r\n");

	return 0;
}

int SPTS_OutputSet (spts_param_t* pstParam)
{
	int rc = 0;

	SPTS_DEBUG("SPTS_OutputSet entry, pstParam = %p\r\n", pstParam);
	if(!pstSpts)
	{
		SPTS_DEBUG("SPTS_OutputSet found NULL pstSpts\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	if(pstParam->m_u16EsCnt < MAX_SPTS_ES)
	{
		memcpy(&pstSpts->m_stSptsParam, pstParam, sizeof(spts_param_t)+sizeof(spts_es_t)*pstParam->m_u16EsCnt);
	}
	else
	{
		SPTS_DEBUG("SPTS_OutputSet found es count[%d] > MAX_SPTS_ES\r\n", pstParam->m_u16EsCnt);
		memcpy(&pstSpts->m_stSptsParam, pstParam, sizeof(spts_param_t)+sizeof(spts_es_t)*MAX_SPTS_ES);
		pstSpts->m_stSptsParam.m_u16EsCnt = MAX_SPTS_ES;
	}
	SPTS_MUTEX_UNLOCK();

	SPTS_DEBUG("SPTS_OutputSet return rc = %d\r\n", rc);

	return rc;
}

int SPTS_GetOutputStatus(spts_status_t* peStatus)
{
	int rc;

	if(!pstSpts || !peStatus)
	{
		SPTS_DEBUG("SPTS_GetOutputStatus found NULL pstSpts or NULL peStatus\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	*peStatus = pstSpts->m_eStatus;
	pstSpts->m_eStatus = SPTS_OUTPUT_NONE;//clear state
	SPTS_MUTEX_UNLOCK();
	
	return 0;
}

int SPTS_GetScrambleStatus(spts_scramble_status_t* peStatus)
{
	int rc;

	if(!pstSpts || !peStatus)
	{
		SPTS_DEBUG("SPTS_GetOutputStatus found NULL pstSpts or NULL peStatus\r\n");
		return -1;
	}

	SPTS_MUTEX_LOCK();
	*peStatus = pstSpts->m_u8EncryProgram;
	SPTS_MUTEX_UNLOCK();
	
	return 0;
}

int SPTS_RegisterOutputFun(pfSPTSDataGot pfOutput)
{
	SPTS_DEBUG("SPTS_RegisterOutputFun entry\r\n");
	pstSpts->m_pfSptsOutput = pfOutput;
	SPTS_DEBUG("SPTS_RegisterOutputFun return 0\r\n");
	return 0;
}

int SPTS_RegisterStartPlayerFun(pfNotifyPlayer pfPlayerNotification)
{
	SPTS_DEBUG("SPTS_RegisterOutputFun entry\r\n");
	pstSpts->m_pfPlayerNotification = pfPlayerNotification;
	SPTS_DEBUG("SPTS_RegisterOutputFun return 0\r\n");
	return 0;
}

int SPTS_Init()
{
	int rc = 0;
	unsigned int i;

	SPTS_DEBUG("SPTS_Init entry\r\n");

	SPTS_CreateCRC32Table(SPTS_CRC32_POLY);

	SPTS_MUTEX_INIT();
	pstSpts = (spts_t*)malloc(sizeof(spts_t)+sizeof(spts_es_t)*MAX_SPTS_ES);
	if(!pstSpts)
	{
		SPTS_DEBUG("SPTS_Init malloc pstSpts memory fail\r\n");
		rc = -1;
	}
	else
	{
		memset(pstSpts, 0, sizeof(spts_t)+sizeof(spts_es_t)*MAX_SPTS_ES);
		pstSpts->m_stSptsParam.m_u16EsCnt = 0;
		for(i=0; i<MAX_SPTS_ES; i++)
			pstSpts->m_ahTsEs[i] = INVALID_FILTER_HANDLE;
		pstSpts->m_hTsPcr = INVALID_FILTER_HANDLE;
		pstSpts->m_hTsPat = INVALID_FILTER_HANDLE;
		pstSpts->m_hTsPmt = INVALID_FILTER_HANDLE;
	}

	SPTS_DEBUG("SPTS_Init return rc = %d\r\n", rc);
	return rc;
}
